package com.chivan.encoder.recorder;

import android.content.Context;
import android.media.AudioFormat;
import android.text.TextUtils;

import com.chivan.encoder.log.Logcat;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;

/*
 * Create by weslywang on 2018/9/27
 * Copyright © Tencent
 *
 * Description:
 */

public class FileUtil {
    public static byte[] getBytes(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return null;
        }

        byte[] buffer = null;
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            File file = new File(filePath);
            fis = new FileInputStream(file);
            bos = new ByteArrayOutputStream(1024);
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            buffer = bos.toByteArray();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return buffer;
    }

    public static void deleteFile(String fileName) {
        File file = new File(fileName);

        if (!file.exists())
            return;

        file.delete();
    }

    /**
     * 原始的音频数据写完了之后，就要生成wav文件。即：这里得到可播放的音频文件
     * WAV文件头部44字节的格式如下：
     * 1.    "RIFF"（4个字节）
     * 固定字符串
     * 2.    录音数据长度 +（44-8） （4个字节）
     * 类型可以是int或long，但必须保证类型占4个字节大小
     * 3.    "WAVE "（4个字节）
     * 固定字符串
     * 4.    "fmt "  （4个字节）
     * 固定字符串，注意最后有一个空格
     * 5.     size1（4个字节）
     * 值为16
     * 6.    format tag（2个字节）
     * 值为1
     * 7.    channel（2个字节）
     * 声道数，1为单声道，2为多声道
     * 8.    sampleRate（4个字节）
     * 采样率，值为8000，16000等
     * 9.    bytePerSec（4个字节）
     * 每秒所需的字节数
     * 10.   blockAlign（2个字节）
     * 每个采样需要的字节数，计算公式：声道数 * 每个采样需要的bit  / 8
     * 11.    bitPerSample（2个字节）
     * 每个采样需要的bit数，一般为8或16
     * 12.    "data"（4个字节）
     * 固定字符串
     * 13.    size2（4个字节）
     * 录音数据的长度，不包括头部长度
     *
     * @param inFilename
     * @param outFilename
     */
    public static void copyWaveFile(long longSampleRate, int channel, int bufferSize, final String inFilename, final String outFilename) {
        FileInputStream in = null;
        FileOutputStream out = null;
        long totalAudioLen = 0;
        long totalDataLen = totalAudioLen + 36;
//        long longSampleRate = sampleRate;
        int channels = 1;
        if (channel == AudioFormat.CHANNEL_IN_MONO)
            channels = 1;
        else if (channel == AudioFormat.CHANNEL_IN_STEREO)
            channels = 2;

        long byteRate = 16 * longSampleRate * channels / 8;
        byte[] data = new byte[bufferSize];
        try {
            in = new FileInputStream(inFilename);
            out = new FileOutputStream(outFilename);
            totalAudioLen = in.getChannel().size();
            totalDataLen = totalAudioLen + 36;
            FileUtil.writeWaveFileHeader(out, totalAudioLen, totalDataLen,
                    longSampleRate, channels, byteRate);
            while (in.read(data) != -1) {
                out.write(data);
            }
            in.close();
            out.close();
            Logcat.i("copyWaveFile successful " + totalDataLen + " Byte");
        } catch (FileNotFoundException e) {
            Logcat.e("copyWaveFile has exception " + e.toString());
        } catch (IOException e) {
            Logcat.e("copyWaveFile has exception " + e.toString());
        }
    }

    /**
     * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
     * 为啥插入这44个字节，这个还真没深入研究，不过你随便打开一个wav
     * 音频的文件，可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
     * 自己特有的头文件。
     */
    public static void writeWaveFileHeader(FileOutputStream out, long totalAudioLen,
                                           long totalDataLen, long longSampleRate, int channels, long byteRate)
            throws IOException {
        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (channels * 16 / 8); // block align
        header[33] = 0;
        header[34] = 16; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
        out.write(header, 0, 44);
    }

    /**
     * 获取本地文件存储路径
     */
    public static String getLocalDirPath(Context context) {
        final File dir = context.getExternalFilesDir(null);
        if (dir == null) {
            return null;
        }
        return dir.getAbsolutePath();//路径：/storage/emulated/0/Android/data/com.tencent.aieducation/files/
    }

    public static String string2Md5(String value) {
        String MD5 = "";

        if (null == value) return MD5;

        try {
            MessageDigest mD = MessageDigest.getInstance("MD5");
            MD5 = byteArrayToHexString(mD.digest(value.getBytes("UTF-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (MD5 == null) MD5 = "";

        return MD5;
    }

    public static String byteArrayToHexString(byte[] data) {
        char[] out = new char[data.length << 1];

        for (int i = 0, j = 0; i < data.length; i++) {
            out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
            out[j++] = DIGITS_LOWER[0x0F & data[i]];
        }
        return new String(out);
    }

    private static final char[] DIGITS_LOWER =
            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String bytesToHexString(byte[] bytes) {
        StringBuilder buf = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) { // 使用String的format方法进行转换
            buf.append(String.format("%02x", new Integer(b & 0xff)));
        }

        return buf.toString().toUpperCase();
    }
}
